package javaTest02.exercise_1;

import java.io.*;
import java.lang.reflect.*;

public class ClassToJava {

    /**
     * @param clazz    需要转换的Class对象
     * @param path     根目录下的相对路径
     * @param fileName Java文件名
     * @description: 将Class对象转换为指定路径下的Java文件
     * @return 是否成功生成java文件
     */
    public boolean generateJavaFile(Class<?> clazz, String path, String fileName) {//将Class对象转换为指定路径的java文件
        return createFile(path, fileName) &&//创建文件
                writeToFile(getFileContent(clazz, path, fileName), path, fileName);//生成文件内容并写入文件
    }

    private boolean createFile(String path, String fileName) {//根据路径名和类名创建java文件
        File dir = new File(path);
        if (!dir.exists() && !dir.mkdirs()){ //文件目录是否存在
            return false;
        }
        File file = new File(path + fileName);
        if (!file.exists()) {//文件是否存在
            try {
                return file.createNewFile();//创建新文件
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    private boolean writeToFile(String fileContent, String path, String fileName) {//将内容写入文件
        FileWriter writer = null;
        try {
            writer = new FileWriter(path + fileName);
            writer.write(fileContent);
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                if (writer != null) {//释放缓存和关闭文件流
                    writer.flush();
                    writer.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return true;
    }

    private String getFileContent(Class<?> clazz, String path, String fileName) {//获取类的属性
        StringBuilder fileBuilder = new StringBuilder();

        addPackageNameToBuilder(fileBuilder, path);//添加包名
        addClassImportFile(clazz,fileBuilder);//添加类的导入语句
        addClassNameToBuilder(fileBuilder, clazz, fileName);//添加类名
        addFieldsToBuilder(fileBuilder, clazz);//添加域
        addConstructorToBuilder(fileBuilder, clazz, fileName);//添加构造方法
        addMethodsToBuilder(fileBuilder, clazz);//添加方法

        return fileBuilder.append("\n}").toString();
    }

    private void addClassImportFile(Class<?> clazz, StringBuilder fileBuilder) {//添加类的导入语句
        Class<?>[] interfaces=clazz.getInterfaces();
        Class<?> superClasses=clazz.getSuperclass();

        for (Class<?> anInterface : interfaces){
            fileBuilder.append("import ").append(anInterface.getName()).append(";\n");
        }

        if (!"Object".equals(getSimpleType(superClasses.getName()))){//直接父类是否为obj
            fileBuilder.append("import ").append(superClasses.getName()).append(";\n\n");
        }
        else{
            fileBuilder.append("\n");
        }
    }

    private void addConstructorToBuilder(StringBuilder fileBuilder, Class<?> clazz, String fileName) {//添加构造方法
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();//构造方法数组
        for (Constructor<?> constructor : constructors) {
            String mod = getModifierName(constructor.getModifiers());//修饰符
            String consName = fileName.substring(0, fileName.indexOf(".java"));//类名
            String parameterStr = getParameterStr(constructor);//参数
            fileBuilder.append(String.format("\t%s %s(%s){\t}\n\n", mod, consName, parameterStr));//字符串拼接
        }
    }

    private void addMethodsToBuilder(StringBuilder fileBuilder, Class<?> clazz) {//添加方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {

            String mod = getModifierName(method.getModifiers());//方法修饰符
            String returnType = getSimpleType(method.getReturnType().toString());//返回值
            String methodName = method.getName();//方法名
            String parameterStr = getParameterStr(method);//参数
            String returnContent = getReturnContent(returnType);//返回内容
            fileBuilder.append(String.format("\t%s %s %s(%s) {\n\t\t%s\n\t}\n",
                    mod, returnType, methodName, parameterStr, returnContent));//字符串格式化
        }
    }

    private String getParameterStr(Executable execution) {//获取可执行类的参数字符串
        Parameter[] parameters = execution.getParameters();//获取参数数组
        StringBuilder parameterStr = new StringBuilder();
        for (int i = 0; i < parameters.length; i++) {
            String pType = getSimpleType(parameters[i].getType().toString());//参数类型
            String pName = parameters[i].getName();//参数名，注:反射无法获取真实的参数名称
            parameterStr.append(pType).append(" ").append(pName);//拼接字符串
            String pEnd = i < parameters.length - 1 ? "," : "";
            parameterStr.append(pEnd);
        }
        return parameterStr.toString();
    }

    private void addFieldsToBuilder(StringBuilder fileBuilder, Class<?> clazz) {//给文件添加域
        Field[] fields = clazz.getDeclaredFields();//获取所有的域
        for (Field field : fields) {
            String mod = getModifierName(field.getModifiers());//修饰符
            String type = getSimpleType(field.getType().toString());//类型
            String fieldName = field.getName();//名称
            fileBuilder.append("\t").append(mod).append(" ").append(type).append(" ").append(fieldName).append(";\n");
        }
        fileBuilder.append("\n");
    }

    private void addClassNameToBuilder(StringBuilder fileBuilder, Class<?> clazz, String fileName) {//给文件添加类名
        String modifier = getModifierName(clazz.getModifiers());//获取修饰符
        String className = fileName.substring(0, fileName.indexOf(".java"));//获取类名
        String interfaceStr=getInterfaceStr(clazz);
        fileBuilder.append(modifier).append(" class ").append(className).append(interfaceStr).append(" {");//书写类名
        fileBuilder.append("\n\n");
    }

    private String getInterfaceStr(Class<?> clazz){//拼接接口和父类字符串
        StringBuilder builder=new StringBuilder();
        String superClassName=getSimpleType(clazz.getSuperclass().getName());
        if (!"Object".equals(superClassName)){
            builder.append(" extends ").append(superClassName);
        }
        Class<?>[] interfaces =clazz.getInterfaces();
        if (interfaces.length>0){
            builder.append(" implements ");
            for (int i = 0; i < interfaces.length; i++) {
                builder.append(getSimpleType(interfaces[i].getName()));
                builder.append(i<interfaces.length-1?" , ":" ");
            }
        }
        return builder.toString();
    }

    private void addPackageNameToBuilder(StringBuilder fileBuilder, String path) {//根据路径给文件添加包名
        String[] arr = path.split("/");//将路径分割
        fileBuilder.append("package ");
        boolean flag = false;
        for (int i = 0; i < arr.length; i++) {//字符串格式化
            if (flag){
                fileBuilder.append(i < arr.length - 1 ? arr[i] + "." : arr[i]);
            }
            if ("src".equals(arr[i])){
                flag = true;
            }
        }
        fileBuilder.append(";\n\n");
    }

    private String getModifierName(int mod) {//获取修饰符
        return Modifier.toString(mod);
    }

    private String getReturnContent(String returnType) {//根据返回值定义返回代码
        String returnContent = "return";
        switch (returnType) {
            case "void":
                break;
            case "float":
            case "double":
            case "long":
            case "int":
                returnContent += " 0";
                break;
            case "boolean":
                returnContent += " false";
                break;
            default:
                returnContent += " null";
                break;
        }
        return returnContent + ";";
    }

    private String getSimpleType(String type) {//获取类型名的简单名称
        if (type.indexOf('.') != -1){
            type = type.substring(type.lastIndexOf('.') + 1);
        }
        return type;
    }

}

